C言語(C89)にもC++(C98)と同じ修飾子(constおよびvolatile)や記憶クラス指定子(extern, static, auto, register, および typedef)が備わっています。ただし、mutable記憶クラス指定子はありません。また、微妙に仕様が異なるものがあるため、ここではそれらについて解説します。
const修飾子
const修飾子の振る舞いは、C++とC言語ではかなり異なるので注意が必要です。
非局所オブジェクトはデフォルトで外部結合
第2回でも触れましたが、const修飾子の有無にかかわらず、関数の外で宣言した非局所オブジェクトは、明示的にstatic記憶クラス指定子を付けないかぎり外部結合になります。
汎整数定数式にはならない
C++では、const修飾子付きの汎整数型オブジェクトは、列挙定数などと同じように汎整数定数式として扱うことができました。しかし、C言語ではそのような例外的な仕様はなく、あくまでも普通のオブジェクトとして振る舞います。したがって、const修飾子付きの汎整数型オブジェクトを、列挙定数の値や配列の要素、caseラベルの値などに使うことはできません。
0 1 2 3 4 5 |
const int N = 10; int array[N]; /* エラー */ enum { foo = N }; /* エラー */ etc. |
mutable記憶クラス指定子
C言語にはmutable記憶クラス指定子はありません。したがって、const修飾子付きで宣言された構造体型のオブジェクトのすべてのメンバは更新することができません。
register記憶クラス指定子
register記憶クラス指定子がヒント情報に過ぎないことは、C言語でも同じです。しかし、あくまでもレジスタに割り付けることを前提としていますので、register記憶クラス指定子を付けて宣言したオブジェクトは、&演算子を使ってアドレスを取得することができません。
0 1 2 3 4 5 6 |
int main(void) { register int a = 0; int *p = &a; /* エラー */ } |
typedef記憶クラス指定子
C++では、同じ内容であれば、同一の翻訳単位にtypedefを使った複数の型定義を記述してもエラーになりませんでした。しかし、C言語ではそうした記述はエラーになります。
0 1 2 3 4 5 6 7 8 |
typedef int a; typedef int a; /* エラー */ int main(void) { return 0; } |